#include "scope.h"
#include "scope_core1.h"

#define SNAP_PSRAM_NUM           1024

static int g_scope_psram_offset = 0;
static int g_scope_psram_step = 0;
static bool g_scope_psram_buffer_ready;
static pingpong_t g_scope_psram_buffer_index;
static scope_snap_data *g_scope_thread1_result;
static scope_adc_data *g_scope_thread1_buffer;
static int g_scope_thread1_cnt;

static int scope_snap_psram_data_points(void)
{
    if (scope_hw_psram_finish() == false) {
        return scope_hw_psram_pos() / 2;
    }
    return psram_size() / 2;
}

static int scope_snap_psram_data_start(void)
{
    if (scope_hw_psram_finish() == false) {
        return 0;
    }
    return scope_hw_psram_pos() / 2;
}

static int __no_inline_not_in_flash_func(scope_snap_psram_read_prepare)(scope_snap_info *info) 
{
    const int32_t step256 = scope_helper_get_step();
    const int32_t half_total_step = (int64_t)step256 * HTTP_FS_IV_NUM >> 9;
    int start = g_scope_psram_offset - half_total_step;
    int end = g_scope_psram_offset + half_total_step;

    info->offset = 0;
    if (start < 0) {  
        info->offset = - (int64_t)start * 256 / step256;
        start = 0;
    }
    const uint32_t psram_max = (uint32_t)scope_snap_psram_data_points();
    if (psram_max == 0) {
        info->length = 0;
        return 0;
    }
    if (end > psram_max - 1) {
        end = psram_max - 1;
    }
    info->length = (end - start) * (int64_t)256 / step256;
    if (info->length > HTTP_FS_IV_NUM) {
        info->length = HTTP_FS_IV_NUM;
    }
    start += scope_snap_psram_data_start();
    return start;
}

// scope_adc_data *scope_snap_psram_get_buffer(int start)
scope_adc_data *__no_inline_not_in_flash_func(scope_snap_psram_get_buffer)(int start)
{
    if (g_scope_psram_buffer_ready == false) {
        psram_read_start(start, (uint32_t *)g_scope_dma_points[PING], sizeof(g_scope_dma_points[PING]));
        psram_read_wait();
        psram_read_start(start + SCOPE_ADC_BUFFER_POINTS, (uint32_t *)g_scope_dma_points[PONG], sizeof(g_scope_dma_points[PONG]));
        g_scope_psram_buffer_ready = true;
        g_scope_psram_buffer_index = PING;
        return g_scope_dma_points[PING];
    }
    psram_read_wait();
    psram_read_start(start + SCOPE_ADC_BUFFER_POINTS, (uint32_t *)g_scope_dma_points[g_scope_psram_buffer_index], sizeof(g_scope_dma_points[PONG]));
    g_scope_psram_buffer_index = !g_scope_psram_buffer_index;
    return g_scope_dma_points[g_scope_psram_buffer_index];
}

// void scope_snap_psram_get_buffer_done(void)
void __no_inline_not_in_flash_func(scope_snap_psram_get_buffer_done)(void)
{
    psram_read_wait();
    g_scope_psram_buffer_ready = false;
    g_scope_psram_buffer_index = PING;
}

void __no_inline_not_in_flash_func(scope_snap_psram_fill_min_max_th0)(scope_snap_data *result, scope_adc_data *buffer, int cnt)
{
    // 展开部分循环以提高性能
    register int32_t ch0_min = result->ch0_min;
    register int32_t ch0_max = result->ch0_max;
    register int32_t ch1_min = result->ch1_min;
    register int32_t ch1_max = result->ch1_max;

    for (int index = 0; index < cnt; index++) {
        if (buffer[index].ch0 > ch0_max) {
            ch0_max = buffer[index].ch0;
        } else if (buffer[index].ch0 < ch0_min) {
            ch0_min = buffer[index].ch0;
        }
        
        if (buffer[index].ch1 > ch1_max) {
            ch1_max = buffer[index].ch1;
        } else if (buffer[index].ch1 < ch1_min) {
            ch1_min = buffer[index].ch1;
        }
    }
    result->ch0_min = ch0_min;
    result->ch0_max = ch0_max;
    result->ch1_min = ch1_min;
    result->ch1_max = ch1_max;
}

void __no_inline_not_in_flash_func(scope_snap_psram_fill_min_max_th1)(void)
{
    scope_snap_data *result = g_scope_thread1_result;
    int cnt = g_scope_thread1_cnt;
    scope_adc_data *buffer = g_scope_thread1_buffer;

    // 展开部分循环以提高性能
    register int32_t ch0_min = result->ch0_min;
    register int32_t ch0_max = result->ch0_max;
    register int32_t ch1_min = result->ch1_min;
    register int32_t ch1_max = result->ch1_max;

    for (int index = 0; index < cnt; index++) {
        if (buffer[index].ch0 > ch0_max) {
            ch0_max = buffer[index].ch0;
        } else if (buffer[index].ch0 < ch0_min) {
            ch0_min = buffer[index].ch0;
        }
        
        if (buffer[index].ch1 > ch1_max) {
            ch1_max = buffer[index].ch1;
        } else if (buffer[index].ch1 < ch1_min) {
            ch1_min = buffer[index].ch1;
        }
    }
    result->ch0_min = ch0_min;
    result->ch0_max = ch0_max;
    result->ch1_min = ch1_min;
    result->ch1_max = ch1_max;
    scope_core1_stop();
}

void __no_inline_not_in_flash_func(scope_snap_psram_fill_min_max)(scope_snap_data *result, scope_adc_data *buffer, int cnt)
{
    scope_snap_data result_th1 = *result;

    if (cnt < 1000) {
        scope_snap_psram_fill_min_max_th0(result, buffer, cnt);
        return;
    }

    int half = cnt / 2;

    g_scope_thread1_result = &result_th1;
    g_scope_thread1_buffer = &buffer[half];
    g_scope_thread1_cnt = cnt - half;

    scope_core1_start(scope_snap_psram_fill_min_max_th1);
    scope_snap_psram_fill_min_max_th0(result, buffer, half);
    scope_core1_wait_finish();
    if (result_th1.ch0_max > result->ch0_max) {
        result->ch0_max = result_th1.ch0_max;
    } 
    if (result_th1.ch0_min < result->ch0_min) {
        result->ch0_min = result_th1.ch0_min;
    }
    if (result_th1.ch1_max > result->ch1_max) {
        result->ch1_max = result_th1.ch1_max;
    }
    if (result_th1.ch1_min < result->ch1_min) {
        result->ch1_min = result_th1.ch1_min;
    }
}

// void scope_snap_psram_read(scope_snap_info *info) 
void __no_inline_not_in_flash_func(scope_snap_psram_read)(scope_snap_info *info) 
{
    const int32_t step256 = scope_helper_get_step();
    const int start = scope_snap_psram_read_prepare(info);
    scope_adc_data *buffer = NULL;
    const uint32_t cnt = step256 >> 8;
    int buffer_map = -10000000;

    // 使用寄存器变量优化循环性能
    register int i;
    register int pos;
    register int index;
    register int piece_end;
    register scope_adc_data *adc;
    register scope_snap_data *curr_snap;

    for (i = 0; i < info->length; i++) {
        uint32_t offset = start + (i * step256 >> 8);
        pos = offset;
        curr_snap = &info->buffer[i];

        // 预先检查是否需要读取新数据块
        if (pos >= buffer_map + SCOPE_ADC_BUFFER_POINTS) {
            buffer_map = pos;
            // psram_read(buffer_map, (uint32_t *)buffer, sizeof(g_scope_dma_points[0]));
            buffer = scope_snap_psram_get_buffer(buffer_map);
        }
        const scope_adc_data *const first = &buffer[pos - buffer_map];

        // 初始化当前采样点的极值
        curr_snap->ch0_min = first->ch0;
        curr_snap->ch0_max = first->ch0;
        curr_snap->ch1_min = first->ch1;
        curr_snap->ch1_max = first->ch1;

        int buffer_left = buffer_map + SCOPE_ADC_BUFFER_POINTS - pos;
        int cnt_left = cnt;
        int piece;

        while (cnt_left > 0) {
            if (buffer_left <= 0) {
                buffer_map = pos;
                // psram_read(buffer_map, (uint32_t *)buffer, sizeof(g_scope_dma_points[0]));
                buffer = scope_snap_psram_get_buffer(buffer_map);
                buffer_left = SCOPE_ADC_BUFFER_POINTS;
            }    

            // 确定本次处理的数据量  
            piece = (cnt_left < buffer_left) ? cnt_left : buffer_left;

            // 计算处理范围
            piece_end = pos - buffer_map + piece;

            scope_snap_psram_fill_min_max(curr_snap, &buffer[pos - buffer_map + 1], piece - 1);
           
            // 更新计数器
            buffer_left -= piece;
            cnt_left -= piece;
            pos += piece;
        }
    }
    scope_helper_buffer_cali_data(info);
    scope_snap_psram_get_buffer_done();
}

void scope_snap_psram_scale(int offset, int step)
{
    uint32_t div, div_bak = g_scope_cfg.time_div_us;
    uint32_t step256 = scope_helper_get_step();
    int index = scope_helper_value_to_index_round_up(g_scope_cfg.time_div_us);
    double align = g_scope_psram_offset + (1.0 * step256 * offset / 256);

    if (step < 0) {
        div = scope_helper_index_to_value(index + 1);
    } else {
        div = scope_helper_index_to_value(index - 1);
    }
    g_scope_cfg.time_div_us = div;
    step256 = scope_helper_get_step();
    if ((step256 >> 8) > psram_size() / 2 / HTTP_FS_IV_NUM * 2) {
        g_scope_cfg.time_div_us = div_bak;
        g_scope_psram_offset = scope_snap_psram_data_points() / 2;
        return;
    }
    if (step256 == 0) {
        g_scope_cfg.time_div_us = div_bak;
        return;
    }
    g_scope_psram_offset = align - (1.0 * step256 * offset / 256);
}

void scope_snap_psram_move(int code)
{
    int step256 = scope_helper_get_step();

    g_scope_psram_offset = g_scope_psram_offset + (code * step256) / 256;
    if (g_scope_psram_offset < 0) {
        g_scope_psram_offset = 0;
    }
    if (g_scope_psram_offset > scope_snap_psram_data_points() - 1) {
        g_scope_psram_offset = scope_snap_psram_data_points() - 1;
    }
}

void scope_snap_psram_start(void)
{
    g_scope_psram_offset = psram_size() / 4;
}

void scope_snap_psram_stop(void)
{
    g_scope_psram_offset = scope_snap_psram_data_points() / 2;
    g_scope_psram_buffer_index = PING;
    g_scope_psram_buffer_ready = false;
}

static int scope_snap_sram_json_open(struct fs_file *file, const char *name, void **priv)
{
    file->len = 512;
    file->index = 0;
    file->data = 0;
    file->flags = 0;
    *priv = (void *)0;
    return 1;
}

int scope_snamp_sram_json_read(struct fs_file *file, char *buffer, int count, void **priv)
{
    #define BUFFER_SIZE 32
    #define MAX_LENGTH 256

    int last = *(uint32_t *)priv;
    scope_adc_data points[BUFFER_SIZE];
    int len = 0;

    if (last == MAX_LENGTH) {
        len = snprintf(buffer + len, sizeof(buffer) - len, "\n]}");
        *(uint32_t *)priv = last + 1;
        return len;
    }
    if (last > MAX_LENGTH) {
        return FS_READ_EOF;
    }
    for (int i = 0; i < BUFFER_SIZE; i++) {
        psram_read(last, (uint32_t *)points, sizeof(points));
        if (i + last == 0) {
            len += snprintf(buffer + len, count - len, "{\"data\":[\n%d, %d", points[i].ch0, points[i].ch1);
        } else {
            len += snprintf(buffer + len, count - len, ",\n%d, %d", points[i].ch0, points[i].ch1);
        }
    }
    *(uint32_t *)priv = last + BUFFER_SIZE;
    return len;
}

void scope_snamp_sram_json_close(struct fs_file *file, void **priv)
{    
}

HTTPD_FILE_DEFINE("/sram.json", scope_snap_sram_json_open, scope_snamp_sram_json_read, NULL, scope_snamp_sram_json_close);

void psram_proc_last_data(char *value)
{
    uint32_t start = scope_snap_psram_data_start();
    scope_adc_data buffer[8];

    psram_read(start - 4, (uint32_t *)buffer, sizeof(buffer));
    log_printf("start: %d\n", start);
    log_printf("data[start - 4]: %d %d\n", buffer[0].ch0, buffer[0].ch1);
    log_printf("data[start - 3]: %d %d\n", buffer[1].ch0, buffer[1].ch1);
    log_printf("data[start - 2]: %d %d\n", buffer[2].ch0, buffer[2].ch1);
    log_printf("data[start - 1]: %d %d\n", buffer[3].ch0, buffer[3].ch1);
    log_printf("data[start + 0]: %d %d\n", buffer[4].ch0, buffer[4].ch1);
    log_printf("data[start + 1]: %d %d\n", buffer[5].ch0, buffer[5].ch1);
    log_printf("data[start + 2]: %d %d\n", buffer[6].ch0, buffer[6].ch1);
    log_printf("data[start + 3]: %d %d\n", buffer[7].ch0, buffer[7].ch1);
}
HTTPD_CGI_PARAM_DEFINE("LastData", psram_proc_last_data);
